package cn.ticsmyc.tools.framework.ioc.factory;

import cn.ticsmyc.tools.framework.ioc.entity.BeanDefinition;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Ticsmyc
 * @date 2021-04-22 16:16
 */
public abstract class AbstractBeanFactory implements BeanFactory{

    /**
     * beanId -> BeanDefinition
     * 所有的beanDefinition
     */
    ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    ThreadLocal<HashMap<String,Object>> earylyBean = new ThreadLocal<HashMap<String, Object>>();

    @Override
    public Object getBean(String beanName) throws Exception {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition == null){
            throw new RuntimeException("找不到"+beanName+"的BeanDefinition");
        }
        return getBeanFromBeanDefinition(beanDefinition);
    }

    @Override
    public Object getBean(Class clazz) throws Exception {
        BeanDefinition beanDefinition = null;
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            Class beanClass = entry.getValue().getBeanClass();
            //如果这个class是所需类型 或者所需类型的子类
            if(clazz.isAssignableFrom(beanClass)){
                beanDefinition = entry.getValue();
            }
        }
        if(beanDefinition == null){
            throw new RuntimeException("找不到"+clazz.getName()+"的BeanDefinition");
        }
        return getBeanFromBeanDefinition(beanDefinition);
    }

    private Object getBeanFromBeanDefinition(BeanDefinition beanDefinition) throws Exception {
        if(beanDefinition.getSingleton()){
            //是单例
            if(beanDefinition.getBean() != null){
                //创建过了
                return beanDefinition.getBean();
            }else{
                /**
                 * 当多个线程使用同一个BeanFactory，针对同一个单例的beanDefinition 调用getBean
                 * 如果没有锁，会创建多个对象
                 */
                synchronized(this){
                    if(beanDefinition.getBean() == null){
                        return doCreateBean(beanDefinition);
                    }else{
                        return beanDefinition.getBean();
                    }
                }
            }
        }else{
            //不是单例  先从earlyBean中找，如果没有就新创建
            HashMap<String, Object> earlyBeanMap = earylyBean.get();
            if(earlyBeanMap!=null && earlyBeanMap.containsKey(beanDefinition.getBeanClassName())){
                return earlyBeanMap.get(beanDefinition.getBeanClassName());
            }else{
                return doCreateBean(beanDefinition);
            }
        }
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws Exception {
        beanDefinitionMap.put(beanName,beanDefinition);
    }

    /**
     * 根据beanDefinition创建bean实例
     * @param beanDefinition
     * @return
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;


    /**
     * 实例化所有单例的Bean
     * @throws Exception
     */
    public void populateBeans()throws Exception{
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            if(entry.getValue().getSingleton() && entry.getValue().getBean()==null){
                doCreateBean(entry.getValue());
            }
        }
    }
}
